package com.gzc.just.play.last.war.sceneserver.benchmark;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;

import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;

import static org.junit.jupiter.api.Assertions.*;

/**
 * 并发性能基准测试
 * 
 * 测试目标:
 * - 并发支持: 1,000+ 玩家
 * - CPU 利用率: < 80%
 * - 内存泄漏: 无
 * - GC 暂停: < 100ms
 */
@BenchmarkMode(Mode.Throughput)
@OutputTimeUnit(TimeUnit.SECONDS)
@State(Scope.Thread)
@Warmup(iterations = 3, time = 1, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Fork(value = 1)
public class ConcurrencyBenchmark {
    
    private Random random = new Random();
    private List<Player> players;
    private Map<String, Player> playerMap;
    private ExecutorService executorService;
    private AtomicInteger messageCounter = new AtomicInteger(0);
    private ReentrantLock lock = new ReentrantLock();
    
    @BeforeEach
    public void setup() {
        // 初始化玩家
        players = new ArrayList<>();
        playerMap = new ConcurrentHashMap<>();
        
        for (int i = 0; i < 1000; i++) {
            Player player = new Player(
                1000 + i,
                "Player" + i,
                20 + (i % 60), // 等级范围 20-79
                1000 + i * 10
            );
            players.add(player);
            playerMap.put(player.name, player);
        }
        
        // 初始化线程池
        executorService = Executors.newFixedThreadPool(10);
    }
    
    @TearDown
    public void tearDown() {
        if (executorService != null && !executorService.isShutdown()) {
            executorService.shutdown();
            try {
                if (!executorService.awaitTermination(5, TimeUnit.SECONDS)) {
                    executorService.shutdownNow();
                }
            } catch (InterruptedException e) {
                executorService.shutdownNow();
                Thread.currentThread().interrupt();
            }
        }
    }
    
    @Benchmark
    public Player benchmarkConcurrentPlayerAccess() {
        // 并发玩家访问
        String playerName = "Player" + random.nextInt(1000);
        return playerMap.get(playerName);
    }
    
    @Benchmark
    public boolean benchmarkConcurrentPlayerUpdate() {
        // 并发玩家更新
        Player player = players.get(random.nextInt(1000));
        if (player != null) {
            // 模拟玩家状态更新
            player.exp += random.nextInt(100);
            player.health = Math.max(0, player.health - random.nextInt(20));
            player.lastActive = System.currentTimeMillis();
            return true;
        }
        return false;
    }
    
    @Benchmark
    public int benchmarkConcurrentMessageProcessing() {
        // 并发消息处理
        int messageCount = 100;
        CountDownLatch latch = new CountDownLatch(messageCount);
        AtomicInteger processedCount = new AtomicInteger(0);
        
        for (int i = 0; i < messageCount; i++) {
            executorService.submit(() -> {
                try {
                    // 模拟消息处理
                    Thread.sleep(random.nextInt(5));
                    processedCount.incrementAndGet();
                    messageCounter.incrementAndGet();
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                } finally {
                    latch.countDown();
                }
            });
        }
        
        try {
            latch.await(1, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        
        return processedCount.get();
    }
    
    @Benchmark
    public List<Player> benchmarkConcurrentPlayerSearch() {
        // 并发玩家搜索
        String searchTerm = "Player" + (random.nextInt(100));
        List<Player> foundPlayers = new ArrayList<>();
        
        for (Player player : players) {
            if (player.name.startsWith(searchTerm)) {
                foundPlayers.add(player);
            }
        }
        
        return foundPlayers;
    }
    
    @Benchmark
    public boolean benchmarkConcurrentResourceAcquisition() {
        // 并发资源获取
        lock.lock();
        try {
            // 模拟资源访问
            Player player = players.get(random.nextInt(1000));
            if (player != null) {
                player.resourceLock++;
                return true;
            }
            return false;
        } finally {
            lock.unlock();
        }
    }
    
    @Benchmark
    public int benchmarkConcurrentPlayerRanking() {
        // 并发玩家排名
        // 使用复制的方式避免并发修改问题
        List<Player> copyPlayers = new ArrayList<>(players);
        
        // 按等级排序
        copyPlayers.sort(Comparator.comparingInt(p -> p.level));
        
        return copyPlayers.size();
    }
    
    @Benchmark
    public Map<Integer, Integer> benchmarkConcurrentStatisticsCalculation() {
        // 并发统计计算
        Map<Integer, Integer> levelDistribution = new ConcurrentHashMap<>();
        
        for (Player player : players) {
            levelDistribution.merge(player.level, 1, Integer::sum);
        }
        
        return levelDistribution;
    }
    
    @Benchmark
    public boolean benchmarkMemoryLeakPrevention() {
        // 内存泄漏预防测试
        List<String> tempData = new ArrayList<>();
        
        // 创建临时数据
        for (int i = 0; i < 100; i++) {
            tempData.add("temp_data_" + i + "_" + System.currentTimeMillis());
        }
        
        // 处理数据后清除引用
        boolean processed = true;
        
        // 清除引用，帮助GC
        tempData.clear();
        tempData = null;
        
        // 强制触发一次小GC（仅在测试中使用）
        System.gc();
        
        return processed;
    }
    
    @Benchmark
    public boolean benchmarkConcurrentLoginLogout() {
        // 并发登录/登出
        int playerId = 1000 + random.nextInt(1000);
        boolean isLogin = random.nextBoolean();
        
        if (isLogin) {
            // 模拟登录
            if (!playerMap.containsKey("Player" + playerId)) {
                Player player = new Player(
                    playerId,
                    "Player" + playerId,
                    20 + (playerId % 60),
                    1000
                );
                playerMap.put(player.name, player);
                return true;
            }
        } else {
            // 模拟登出
            Player removed = playerMap.remove("Player" + playerId);
            return removed != null;
        }
        
        return false;
    }
    
    @Benchmark
    public List<Player> benchmarkConcurrentTeamFormation() {
        // 并发组队
        List<Player> team = new ArrayList<>();
        int teamSize = 5;
        int startIndex = random.nextInt(1000 - teamSize);
        
        for (int i = startIndex; i < startIndex + teamSize; i++) {
            team.add(players.get(i));
        }
        
        return team;
    }
    
    @Benchmark
    public void benchmarkConcurrentBattleSimulation() {
        // 并发战斗模拟
        int battleCount = 10;
        CountDownLatch latch = new CountDownLatch(battleCount);
        
        for (int i = 0; i < battleCount; i++) {
            executorService.submit(() -> {
                try {
                    // 简单的战斗模拟
                    Player player1 = players.get(random.nextInt(1000));
                    Player player2 = players.get(random.nextInt(1000));
                    
                    if (player1 != null && player2 != null && player1 != player2) {
                        simulateBattle(player1, player2);
                    }
                } finally {
                    latch.countDown();
                }
            });
        }
        
        try {
            latch.await(2, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
    
    private void simulateBattle(Player p1, Player p2) {
        // 简化的战斗逻辑
        int rounds = 10;
        boolean p1Turn = true;
        
        for (int i = 0; i < rounds; i++) {
            if (p1Turn) {
                p2.health = Math.max(0, p2.health - random.nextInt(50));
            } else {
                p1.health = Math.max(0, p1.health - random.nextInt(50));
            }
            
            p1Turn = !p1Turn;
            
            // 如果任一方死亡，结束战斗
            if (p1.health <= 0 || p2.health <= 0) {
                break;
            }
            
            // 短暂延迟
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                break;
            }
        }
    }
    
    // 简化的内部类
    private static class Player {
        int id;
        String name;
        int level;
        int health;
        int maxHealth = 1000;
        int exp;
        long lastActive = System.currentTimeMillis();
        int resourceLock = 0;
        
        public Player(int id, String name, int level, int health) {
            this.id = id;
            this.name = name;
            this.level = level;
            this.health = health;
        }
    }
    
    /**
     * JUnit 测试方法 - 验证基准测试是否可以正常工作
     */
    @Test
    public void testConcurrencySetup() {
        // 测试设置是否正确
        assertNotNull(players, "Players should not be null");
        assertFalse(players.isEmpty(), "Players should not be empty");
        assertNotNull(playerMap, "Player map should not be null");
        assertFalse(playerMap.isEmpty(), "Player map should not be empty");
        assertNotNull(executorService, "Executor service should not be null");
        
        // 测试方法可以正常运行
        Player player = benchmarkConcurrentPlayerAccess();
        assertNotNull(player, "Player should be found");
        
        boolean updated = benchmarkConcurrentPlayerUpdate();
        assertTrue(updated, "Player update should succeed");
        
        int processed = benchmarkConcurrentMessageProcessing();
        assertTrue(processed > 0, "Messages should be processed");
        
        boolean acquired = benchmarkConcurrentResourceAcquisition();
        assertTrue(acquired, "Resource should be acquired");
    }
    
    /**
     * JUnit 测试方法 - 验证基准测试方法的性能
     */
    @Test
    public void testConcurrencyPerformance() {
        // 初始化测试数据
        setup();
        
        // 测试并发玩家访问性能
        long startTime = System.nanoTime();
        for (int i = 0; i < 1000; i++) {
            benchmarkConcurrentPlayerAccess();
        }
        long duration = System.nanoTime() - startTime;
        
        // 验证在合理时间内完成（1秒内）
        assertTrue(duration < 1_000_000_000L, 
            "Concurrent player access should complete within 1 second");
        
        // 测试并发玩家更新性能
        startTime = System.nanoTime();
        for (int i = 0; i < 500; i++) { // 更新操作更复杂，次数少一些
            benchmarkConcurrentPlayerUpdate();
        }
        duration = System.nanoTime() - startTime;
        
        // 验证在合理时间内完成（1秒内）
        assertTrue(duration < 1_000_000_000L, 
            "Concurrent player update should complete within 1 second");
    }
}